package chat.MsgEvent;

import java.util.*;
import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Source code from "Java Distributed Computing", by Jim Farley.
 *
 * Class: EventTransceiver
 * Example: 6-13
 * Description: One end of an event-based network communication scheme.
 */
public class EventTransceiver extends Thread implements EventHandler {
    // A hashtable of handlers for specific events

    private Hashtable handlers = new Hashtable();
    // A list of handlers that want all events
    private Vector globalHandlers = new Vector();
    // Our connection to a remote agent
    InputStream evIn = null;
    OutputStream evOut = null;
    BufferedReader in = null;
    boolean stop = false;

    public EventTransceiver(Socket sock) {
        this.sock = sock;
        try {
            in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        } catch (IOException ex) {
            Logger.getLogger(EventTransceiver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    protected Socket sock = null;

    /**
     * Get the value of sock
     *
     * @return the value of sock
     */
    public Socket getSock() {
        return sock;
    }

    void connect(InetAddress a, int port) {
        try {
            sock = new Socket(a, port);
            evIn = sock.getInputStream();
            evOut = sock.getOutputStream();

        } catch (Exception e) {
            evIn = null;
            evOut = null;
        }
    }

    public EventTransceiver(InputStream in, OutputStream out) {
        setStreams(in, out);
    }

    void setStreams(InputStream in, OutputStream out) {
        evIn = in;
        evOut = out;
    }

    public void sendEvent(EventObject ev) throws IOException {
        ObjectOutputStream oout = new ObjectOutputStream(evOut);
        oout.writeObject(ev);
    }

    EventObject receiveEvent() throws IOException {
   
        //ObjectInputStream oin = new ObjectInputStream(evIn);
        EventObject ev = null;
   /*
        try {

            String rawMsg = in.readLine();
            System.out.println("==>" + rawMsg);
            String[] names = rawMsg.split(" ");
            String msgType = names[0];
            //System.out.println(msgType);

            /// 公子乖 -　Parse 參數
            if (msgType.equals("/show")) {
                ev = new ShowEvent(rawMsg.substring(5), ShowEvent.NEWLINE);
            } else if (msgType.equals("/LoginOK")) {
                ev = new LoginOKEvent(rawMsg.substring(9));
            } else if (msgType.equals("/obj")) {
                // /obj yoyo chat.CircleBean 10 10
                String cmd = "";
                for (int i = 1; i < names.length; i++) {
                    //cmd + = (names[i] + " ");
                    cmd += names[i];
                    cmd += " ";
                }
                ev = new DrawBeanEvent(cmd);
            } else if (msgType.equals("/move")) {
                String cmd = "";
                for (int i = 1; i < names.length; i++) {
                    //cmd + = (names[i] + " ");
                    cmd += names[i];
                    cmd += " ";
                }
                ev = new MoveBeanEvent(cmd);
            } else if (msgType.equals("/change")) {
                String cmd = "";
                for (int i = 1; i < names.length; i++) {
                    cmd += names[i];
                    cmd += " ";
                }
                ev = new ChangeBeanEvent(cmd);
            }else if(msgType.equals("/kick")){
                ev = new KickUserEvent(names[1]);
            }else if(msgType.equals("/msg")){
                ev =  new MsgPostEvent(rawMsg.substring(names[0].length()+1));
            }else if(msgType.equals("/post")){
                ev =  new PostEvent(rawMsg.substring(names[0].length()+1));
            }


            //ev = (EventObject)oin.readObject();
            //System.out.println(ev);
        } catch (ClassCastException e) {
            System.out.println("Non-event object sent to EventTransceiver");
        }
//    catch (ClassNotFoundException e2) {
//      System.out.println("Unresolvable object type sent to EventTransceiver");
//    }
*/
        return ev;
    }

    void distributeEvent(EventObject ev) {
        // Send event to all "global" handlers
        Enumeration e = globalHandlers.elements();
        while (e.hasMoreElements()) {
            EventHandler h = (EventHandler) e.nextElement();
            h.handleEvent(ev);
        }

        // Send event to handlers targetting the event's class
        Class evClass = ev.getClass();
        Vector evHandlers = (Vector) handlers.get(evClass);
        e = evHandlers.elements();
        while (e.hasMoreElements()) {
            EventHandler h = (EventHandler) e.nextElement();
            h.handleEvent(ev);
        }
    }

    // No default behavior for handling events...
    public void handleEvent(EventObject e) {
    }

    // Register a handler that wants all events.
    public void addHandler(EventHandler eh) {
        if (!globalHandlers.contains(eh)) {
            globalHandlers.addElement(eh);
        }
    }

    // Register a handler for a specific type of event
    public void addHandler(EventHandler eh, EventObject e) {
        Class eClass = e.getClass();
        addHandler(eh, eClass);
    }

    public void addHandler(EventHandler eh, Class ec) {
        Vector evHandlers = (Vector) handlers.get(ec);
        if (evHandlers == null) {
            evHandlers = new Vector();
            handlers.put(ec, evHandlers);
        }
        if (!evHandlers.contains(eh)) {
            evHandlers.addElement(eh);
        }
    }

    // Remove a handler from all lists
    public void removeHandler(EventHandler eh) {
        globalHandlers.removeElement(eh);
        Enumeration ecList = handlers.keys();
        while (ecList.hasMoreElements()) {
            Vector evHandlers =
                    (Vector) handlers.get(ecList.nextElement());
            if (evHandlers != null) {
                evHandlers.removeElement(eh);
            }
        }
    }

    // Remove a handler for a specific event type
    public void removeHandler(EventHandler eh, EventObject e) {
        removeHandler(eh, e.getClass());
    }

    public void removeHandler(EventHandler eh, Class ec) {
        Vector evHandlers = (Vector) handlers.get(ec);
        if (evHandlers != null) {
            evHandlers.removeElement(eh);
        }
    }

    // If run as an independent thread, just loop listening
    // for events from the remote agent, and distribute them
    // to registered handlers
    public void run() {
        try {
            while (!stop) {

                EventObject e = receiveEvent();
                //System.out.println(e);
                if (e != null) {
                    distributeEvent(e);
                }
            }
        } // Treat an IOException as termination of the event
        // input stream, and let this handler thread die
        catch (IOException e) {
        }
    }

    public void leave() {
        //throw new UnsupportedOperationException("Not yet implemented");
        stop = true;
    }
}
